package com.ruoyi.system.service.impl;

import java.sql.Connection;
import java.util.*;

import com.alibaba.druid.util.JdbcUtils;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.system.mapper.SysFormconfigMapper;
import com.ruoyi.system.domain.SysFormconfig;
import com.ruoyi.system.service.ISysFormconfigService;

/**
 * 表单配置Service业务层处理
 *
 * @author sunwei
 * @date 2025-10-20
 */
@Service
public class SysFormconfigServiceImpl implements ISysFormconfigService {
    @Autowired
    private SysFormconfigMapper sysFormconfigMapper;
    /**
     * 查询表单配置
     *
     * @param id 表单配置主键
     * @return 表单配置
     */
    @Override
    public SysFormconfig selectSysFormconfigById(Long id) {
        return sysFormconfigMapper.selectSysFormconfigById(id);
    }

    /**
     * 查询表单配置列表
     *
     * @param sysFormconfig 表单配置
     * @return 表单配置
     */
    @Override
    public List<SysFormconfig> selectSysFormconfigList(SysFormconfig sysFormconfig) {
        return sysFormconfigMapper.selectSysFormconfigList(sysFormconfig);
    }

    /**
     * 新增表单配置
     *
     * @param sysFormconfig 表单配置
     * @return 结果
     */
    @Override
    public int insertSysFormconfig(SysFormconfig sysFormconfig) {
        sysFormconfig.setCreateTime(DateUtils.getNowDate());
        CheckFormAndCheckTable(sysFormconfig);
        return sysFormconfigMapper.insertSysFormconfig(sysFormconfig);
    }

    /**
     * 修改表单配置
     *
     * @param sysFormconfig 表单配置
     * @return 结果
     */
    @Override
    public int updateSysFormconfig(SysFormconfig sysFormconfig) {
        sysFormconfig.setUpdateTime(DateUtils.getNowDate());
        CheckFormAndCheckTable(sysFormconfig);
        return sysFormconfigMapper.updateSysFormconfig(sysFormconfig);
    }


    /**
     * 批量删除表单配置
     *
     * @param ids 需要删除的表单配置主键
     * @return 结果
     */
    @Override
    public int deleteSysFormconfigByIds(Long[] ids) {
        return sysFormconfigMapper.deleteSysFormconfigByIds(ids);
    }

    /**
     * 删除表单配置信息
     *
     * @param id 表单配置主键
     * @return 结果
     */
    @Override
    public int deleteSysFormconfigById(Long id) {
        return sysFormconfigMapper.deleteSysFormconfigById(id);
    }

    /**
     * 检查表单编码是否重复和更新数据表列配置
     * @param sysFormconfig 表单配置对象
     */
    private void CheckFormAndCheckTable(SysFormconfig sysFormconfig) {
        // 检查表单编码是否重复，防止创建重复编码的表单
        checkFormCodeDuplicate(sysFormconfig);
        // 解析表单字段，从JSON配置中提取需要映射到数据库的字段信息
        List<Map<String, String>> fields = parseFormFields(sysFormconfig);

        // 处理数据表，根据表单配置决定是创建新表还是更新现有表结构
        handleDataTable(sysFormconfig, fields);
    }

    /**
     * 检查表单编码是否重复
     * @param sysFormconfig 表单配置对象
     */
    private void checkFormCodeDuplicate(SysFormconfig sysFormconfig) {
        // 创建查询条件对象，用于检查表单编码是否已存在
        SysFormconfig queryformconfig = new SysFormconfig();
        // 设置要查询的表单编码
        queryformconfig.setFormCode(sysFormconfig.getFormCode());
        // 查询数据库中是否存在相同编码的表单
        List<SysFormconfig> sysFormconfigs = sysFormconfigMapper.selectSysFormconfigList(queryformconfig);
        // 如果存在相同编码且不是当前正在编辑的记录，则抛出重复异常
        if (sysFormconfigs.size() > 0 && sysFormconfigs.get(0).getId() != sysFormconfig.getId()) {
            throw new RuntimeException("表单编码重复");
        }
    }


    /**
     * 解析表单字段
     * @param sysFormconfig 表单配置对象
     * @return 字段信息列表
     */
    private List<Map<String, String>> parseFormFields(SysFormconfig sysFormconfig) {
        // 获取表单JSON配置字符串
        String formJson = sysFormconfig.getFormJson();
        // 将JSON字符串解析为JSONObject对象
        JSONObject jsonObject = JSONObject.parseObject(formJson);
        // 获取schemas数组，包含表单的所有组件配置
        JSONArray schemas = jsonObject.getJSONArray("schemas");
        // 创建字段列表，用于存储解析出的字段信息
        List<Map<String, String>> fields = new ArrayList<>();
        // 遍历schemas数组，解析每个组件的字段信息
        for (int i = 0; i < schemas.size(); i++) {
            // 获取当前schema对象
            JSONObject schema = schemas.getJSONObject(i);
            // 递归解析schema中的字段信息
            getFields(schema, fields);
        }
        // 打印解析出的字段信息，用于调试
        System.out.println(fields);
        // 返回解析出的字段列表
        return fields;
    }


    /**
     * 处理数据表
     * @param sysFormconfig 表单配置对象
     * @param fields 字段列表
     */
    private void handleDataTable(SysFormconfig sysFormconfig, List<Map<String, String>> fields) {
        // 查询数据库中是否存在对应表单编码的数据表
        int tableCount = sysFormconfigMapper.selectTable(sysFormconfig);
        // 如果表存在，则更新表结构
        if (tableCount > 0) {
            // 数据表存在则更新数据表列配置
            updateDataTableColumns(sysFormconfig, fields);
        } else {
            // 如果表不存在，则创建新表
            // 数据表不存在，创建数据表
            createDataTable(sysFormconfig, fields);
        }
    }


    /**
     * 据表存在则更新数据表列配置
     * @param sysFormconfig 表单配置对象
     * @param fields 字段列表
     */
    private void updateDataTableColumns(SysFormconfig sysFormconfig, List<Map<String, String>> fields) {
        // 查询数据库中现有表的字段信息
        List<Map<String, String>> dbFields = sysFormconfigMapper.selectDbFields(sysFormconfig);
        // 生成字段变更SQL语句，包括新增字段和重命名旧字段
        List<String> alterSql = getFiledsSql(fields, dbFields, sysFormconfig);
        // 打印生成的SQL语句，用于调试
        System.out.println(alterSql);
        // 执行所有生成的SQL语句
        for (String sql : alterSql) {
            sysFormconfigMapper.excuteSql(sql);
        }
    }


    /**
     * 数据表不存在，创建数据表
     * @param sysFormconfig 表单配置对象
     * @param fields 字段列表
     */
    private void createDataTable(SysFormconfig sysFormconfig, List<Map<String, String>> fields) {
        // 创建用于存储字段注释SQL语句的列表
        List<String> commentSqlList = new ArrayList<>();
        // 构建创建表的SQL语句
        String createTableSql = buildCreateTableSql(sysFormconfig, fields, commentSqlList);
        // 打印创建表的SQL语句，用于调试
        System.out.println(createTableSql);
        // 执行创建表的SQL语句
        sysFormconfigMapper.excuteSql(createTableSql);
        // 执行所有字段注释SQL语句
        for (String sql : commentSqlList) {
            sysFormconfigMapper.excuteSql(sql);
        }
    }


    private String buildCreateTableSql(SysFormconfig sysFormconfig, List<Map<String, String>> fields, List<String> commentSqlList) {
        // 创建StringBuilder用于构建SQL语句
        StringBuilder sqlBuilder = new StringBuilder();
        // 添加创建表语句的开头部分，包含表名
        sqlBuilder.append("CREATE TABLE \"").append(sysFormconfig.getFormCode()).append("\" (");
        // 添加主键ID字段定义
        sqlBuilder.append("\"id\" bigint NOT NULL,");

        // 遍历所有字段，构建字段定义部分
        for (int i = 0; i < fields.size(); i++) {
            // 获取当前字段信息
            Map<String, String> field = fields.get(i);
            // 添加字段名和类型定义
            sqlBuilder.append("\"").append(field.get("field")).append("\" ")
                    .append(field.get("type"));

            // 只有当长度大于0时才添加长度限制
            if (!"0".equals(field.get("length")) && !"text".equals(field.get("type").toLowerCase())) {
                // 添加字段长度定义
                sqlBuilder.append("(").append(field.get("length")).append(")");
            }

            // 添加逗号分隔符，最后一个字段后不加逗号
            if (i < fields.size() - 1) {
                sqlBuilder.append(",");
            }

            // 构建字段注释SQL语句
            String commentSql = "COMMENT ON COLUMN \"" + sysFormconfig.getFormCode() + "\".\"" +
                    field.get("field") + "\" IS '" + field.get("label") + "'";
            // 将注释SQL语句添加到列表中
            commentSqlList.add(commentSql);
        }
        // 添加主键约束定义
        sqlBuilder.append(", PRIMARY KEY (\"id\"))");
        // 返回完整的创建表SQL语句
        return sqlBuilder.toString();
    }


    /**
     * @param fileds 表单字段列表
     * @param dbFields 数据库字段列表
     * @param sysFormconfig 表单配置对象
     * @return 字段变更SQL语句列表
     */
    private List<String> getFiledsSql(List<Map<String, String>> fileds, List<Map<String, String>> dbFields, SysFormconfig sysFormconfig) {
        // 创建用于存储SQL语句的列表
        List<String> aleterSql = new ArrayList<>();
        // 创建副本用于操作，避免直接修改原始列表
        List<Map<String, String>> filedsCopy = new ArrayList<>(fileds);
        List<Map<String, String>> dbFieldsCopy = new ArrayList<>(dbFields);

        // 移除fileds与dbFields中完全一致的字段
        Iterator<Map<String, String>> filedsIterator = filedsCopy.iterator();
        while (filedsIterator.hasNext()) {
            Map<String, String> formField = filedsIterator.next();
            Iterator<Map<String, String>> dbFieldsIterator = dbFieldsCopy.iterator();

            while (dbFieldsIterator.hasNext()) {
                Map<String, String> dbField = dbFieldsIterator.next();
                // 检查字段名和数据类型是否一致
                boolean isFieldNameEqual = formField.get("field").equalsIgnoreCase(dbField.get("COLUMN_NAME"));
                boolean isFieldTypeEqual = formField.get("type").equalsIgnoreCase(dbField.get("DATA_TYPE"));

                // 对于textarea类型，只需要比较字段名和类型，不需要比较长度
                boolean isFieldLengthEqual = true;
                if (!formField.get("type").toLowerCase().contains("text") && !formField.get("type").toLowerCase().contains("int")) {
                    // 非textarea类型需要比较长度
                    isFieldLengthEqual = Objects.equals(formField.get("length"), String.valueOf(dbField.get("data_length")));
                }

                if (isFieldNameEqual && isFieldTypeEqual && isFieldLengthEqual) {
                    // 完全一致则从两个列表中都移除
                    filedsIterator.remove();
                    dbFieldsIterator.remove();
                    break;
                }
            }
        }

        // 对dbFields中剩余的所有字段进行重命名（字段名加时间）
        for (Map<String, String> dbField : dbFieldsCopy) {
            // 构建重命名字段的SQL语句
            String renameSql = "ALTER TABLE \"" + sysFormconfig.getFormCode() +
                    "\" RENAME COLUMN \"" + dbField.get("COLUMN_NAME") +
                    "\" TO \"" + dbField.get("COLUMN_NAME") + "_" + DateUtils.dateTimeNow() + "\"";
            // 将重命名SQL语句添加到列表中
            aleterSql.add(renameSql);
        }

        // 根据fileds中剩余的字段创建新字段
        for (Map<String, String> formField : filedsCopy) {
            // 构建添加字段的SQL语句
            String addColumnSql = "ALTER TABLE \"" + sysFormconfig.getFormCode() +
                    "\" ADD COLUMN \"" + formField.get("field") +
                    "\" " + formField.get("type");
            // 如果字段需要长度定义，则添加长度
            if (!"0".equals(formField.get("length")) && !"text".equalsIgnoreCase(formField.get("type"))) {
                addColumnSql += "(" + formField.get("length") + ")";
            }
            // 将添加字段SQL语句添加到列表中
            aleterSql.add(addColumnSql);

            // 使用COMMENT ON语法添加字段描述
            String commentSql = "COMMENT ON COLUMN \"" + sysFormconfig.getFormCode() + "\".\"" +
                    formField.get("field") + "\" IS '" + formField.get("label") + "'";
            // 将注释SQL语句添加到列表中
            aleterSql.add(commentSql);
        }

        // 返回所有生成的SQL语句列表
        return aleterSql;
    }


    //获取字段类型
    public String filedType = "community-select,epic-input,radio,input,textarea,number,checkbox,select,cascader,date,upload-file,upload-image,switch，slider，color-picker,Table,administrative";

    /**
     * 递归解析json,获取表单字段
     *
     * @param schema JSON模式对象
     * @param fileds 用于收集字段信息的列表
     */
    private void getFields(JSONObject schema, List<Map<String, String>> fileds) {
        // 检查当前schema是否包含children属性
        if (schema.containsKey("children")) {
            // 获取children数组
            JSONArray children = schema.getJSONArray("children");
            // 遍历所有子节点
            for (int i = 0; i < children.size(); i++) {
                // 获取当前子节点
                JSONObject child = children.getJSONObject(i);
                // 获取节点类型
                String type = child.getString("type");
                // 检查节点类型是否属于需要存储到数据库的字段类型
                if(type.contains("table")){
                    type = "TABLE";
                }
                if (filedType.contains(type) ) {
                    // 创建字段信息Map
                    Map<String, String> filed = new HashMap<>();
                    // 初始化字段长度为0
                    int length = 0;
                    // 如果节点包含length属性，则获取长度值
                    if (child.get("length") != null) {
                        length = child.getIntValue("length");
                    }
                    // 设置字段名（使用组件ID）
                    filed.put("field", String.valueOf(child.get("field")));
                    // 根据组件类型获取数据库类型和长度
                    String[] dbProps = getDbTypeAndLengthByFiled(type);
                    // 设置字段类型
                    filed.put("type", dbProps[0]);
                    // 设置字段长度（优先使用自定义长度，否则使用默认长度）
                    filed.put("length", length > 0 ? String.valueOf(length) : dbProps[1]);
                    // 设置字段标签（显示名称）
                    filed.put("label", String.valueOf(child.get("label")));
                    // 将构建好的字段map添加到fileds列表中
                    fileds.add(filed);
                }
                // 递归处理子节点
                getFields(child, fileds);
            }
        }
    }

    /**
     * 根据字段类型获取数据库类型和长度
     *
     * @param type
     * @return
     */
    private String[] getDbTypeAndLengthByFiled(String type) {
        switch (type) {
            case "radio":
                return new String[]{"VARCHAR2", "255"};
            case "input":
                return new String[]{"VARCHAR2", "255"};
            case "epic-input":
                return new String[]{"VARCHAR2", "255"};
            case "community-select":
                return new String[]{"VARCHAR2", "255"};
            case "textarea":
                return new String[]{"text", "2147483647"};
            case "number":
                return new String[]{"int", "0"};
            case "checkbox":
                return new String[]{"VARCHAR2", "255"};
            case "select":
                return new String[]{"VARCHAR2", "255"};
            case "cascader":
                return new String[]{"VARCHAR2", "255"};
            case "date":
                return new String[]{"datetime", "0"};
            case "upload-file":
                return new String[]{"VARCHAR2", "255"};
            case "upload-image":
                return new String[]{"VARCHAR2", "255"};
            case "switch":
                return new String[]{"tinyint", "0"};
            case "slider":
                return new String[]{"int", "0"};
            case "color-picker":
                return new String[]{"VARCHAR2", "255"};
            case "Table":
                return new String[]{"text", "2147483647"};
            case "administrative":
                return new String[]{"VARCHAR2", "255"};
            default:
                return new String[]{"VARCHAR2", "255"};
        }
    }
    /**
     * 获取KPI
     *
     * @param sysFormconfig 表单配置
     * @return 结果
     */
    /**
     * 获取KPI
     *
     * @param sysFormconfig 表单配置
     * * @return 结果
     */
    public List<Map<String, Object>> getCityKpi(SysFormconfig sysFormconfig) {
        List<Map<String, Object>> kpis = new ArrayList<>();
        // 获取JDBC链接
        Connection connection = null;
        java.sql.Statement statement = null;
        java.sql.ResultSet resultSet = null;

        try {
            // 配置其他数据库的连接信息
            String url = "jdbc:dm://101.200.63.48:5237/GDONEMAP"; // 示例Oracle连接
            String username = "GDONEMAP";
            String password = "GDONEMAP1q2w3e4r";
            // 加载数据库驱动
            Class.forName("dm.jdbc.driver.DmDriver"); // Oracle驱动
            // 建立连接
            connection = java.sql.DriverManager.getConnection(url, username, password);
            // 创建Statement对象
            statement = connection.createStatement();

            // 执行查询IDT_INDICATORS表中所有数据的SQL
            String sql = "SELECT * FROM IDT_INDICATORS";
            resultSet = statement.executeQuery(sql);

            // 处理查询结果
            while (resultSet.next()) {
                Map<String, Object> row = new HashMap<>();
                // 获取ResultSet的元数据
                java.sql.ResultSetMetaData metaData = resultSet.getMetaData();
                int columnCount = metaData.getColumnCount();

                // 遍历每一列，将数据放入Map中
                for (int i = 1; i <= columnCount; i++) {
                    String columnName = metaData.getColumnName(i);
                    Object value = resultSet.getObject(i);
                    row.put(columnName, value);
                }

                kpis.add(row);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("查询KPI数据失败: " + e.getMessage());
        } finally {
            // 关闭资源
            try {
                if (resultSet != null) {
                    resultSet.close();
                }
                if (statement != null) {
                    statement.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return kpis;
    }

}
